package com.csw.android.ffmpegtest.audio

import android.content.Context
import android.media.AudioAttributes
import android.media.AudioFormat
import android.media.AudioManager
import android.media.AudioTrack
import com.csw.android.dev_utils.ex.CloseableEx.closeIgnoreException
import com.csw.android.dev_utils.handler.MainHandler
import com.csw.android.ffmpegtest.app.MyApplication
import java.io.DataInputStream
import java.io.File
import java.io.FileInputStream


/**
 * 常用的音频格式如mp3等都是通过编码的音频数据，AudioTrack只能播放已经解码成PCM数据的音频流。
 * 能播放mp3等音乐格式的播放器，如mediaPlayer，都是解封装，解码，然后拿到PCM数据通过audioTrack进行播放
 */
class PCMAudioTrackHelper(val filePath: String, val onAudioTrackListener: OnAudioTrackListener) {

    //音频流类型，用于告诉系统当前播放的音频属于那种类型，方便系统控制哪些类型的音频优先播放
    private val streamType = AudioManager.STREAM_MUSIC

    // 采样率
    // 44100是目前的标准，但是某些设备仍然支持22050，16000，11025
    // 采样频率一般共分为22.05KHz、44.1KHz、48KHz三个等级
    private val sampleRateInHz = 16000

    // 音频通道 单声道
    private val channelConfig = AudioFormat.CHANNEL_OUT_MONO

    // 音频格式：PCM编码
    private val audioFormat = AudioFormat.ENCODING_PCM_16BIT

    //audioRecord能接受的最小的buffer大小
    private val bufferSize =
        AudioTrack.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat)

    //音频播放模式：流
    private val mode = AudioTrack.MODE_STREAM

    //音频播放处理类
    private val audioTrack: AudioTrack

    //音频播放id
    private val sessionId: Int

    private val mainHandler = MainHandler()

    init {
        val audioManager =
            MyApplication.instance.getSystemService(Context.AUDIO_SERVICE) as AudioManager
        sessionId = audioManager.generateAudioSessionId()
        audioTrack = AudioTrack(
            AudioAttributes.Builder()
                .setLegacyStreamType(streamType)
                .build(),
            AudioFormat.Builder()
                .setChannelMask(channelConfig)
                .setEncoding(audioFormat)
                .setSampleRate(sampleRateInHz)
                .build(),
            bufferSize,
            mode,
            sessionId
        )
    }

    private var running = false
    private var lastNoticeTime = 0L
    fun start() {
        if (running) {
            return
        }
        running = true
        lastNoticeTime = System.currentTimeMillis()
        mainHandler.post {
            onAudioTrackListener.onStart(this)
        }
        Thread {
            var dis: DataInputStream? = null
            try {
                audioTrack.play()
                val file = File(filePath)
                val totalLength = file.length()
                var readLength = 0L
                dis = DataInputStream(FileInputStream(file))
                val buff = ByteArray(bufferSize)
                var len: Int
                var currTime: Long
                while (dis.read(buff).also { len = it } > 0) {
                    if (!running) {
                        break
                    }
                    readLength += len
                    audioTrack.write(buff, 0, len)
                    currTime = System.currentTimeMillis()
                    if (currTime - lastNoticeTime >= 200) {
                        lastNoticeTime = currTime
                        mainHandler.post {
                            onAudioTrackListener.onPlayProgressChanged(
                                this,
                                totalLength,
                                readLength
                            )
                        }
                    }
                }
            } catch (e: Exception) {
                e.printStackTrace()
            } finally {
                mainHandler.post {
                    onAudioTrackListener.onStop(this)
                }
                audioTrack.release()
                dis.closeIgnoreException()
            }
        }.start()
    }

    fun stop() {
        running = false
    }

    interface OnAudioTrackListener {
        fun onStart(helper: PCMAudioTrackHelper)
        fun onPlayProgressChanged(helper: PCMAudioTrackHelper, totalLength: Long, readLength: Long)
        fun onStop(helper: PCMAudioTrackHelper)
    }
}